package net.gagnat.android.trackit.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;

import net.gagnat.android.trackit.db.DatabaseHelper;
import net.gagnat.android.trackit.domain.LogEntry;
import net.gagnat.android.trackit.util.TrackItConstants.LogEntryColumns;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;

class LogEntryDbManager extends AbstractDbManager {

	private static final String TAG_SEPARATOR = ";";

	private static final String[] PROJECTION = new String[] { LogEntryColumns._ID, // 0
			LogEntryColumns.TITLE, // 1
			LogEntryColumns.CREATED_DATE, // 2
			LogEntryColumns.TAGS // 3
	};

	private static HashMap<String, String> sLogEntriesProjectionMap;

	public LogEntryDbManager(Context context) {
		super(context);
	}

	public List<LogEntry> list() {
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor cursor = db.query(DatabaseHelper.LOG_ENTRY_TABLE_NAME, PROJECTION, null, null, null, null, LogEntryColumns.DEFAULT_SORT_ORDER);

		List<LogEntry> logEntries = new ArrayList<LogEntry>();
		if (cursor.moveToFirst()) {
			do {
				logEntries.add(retrieveLogEntry(cursor));
			} while (cursor.moveToNext());
		}
		return logEntries;
	}

	public LogEntry get(Long id) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

		qb.setTables(DatabaseHelper.LOG_ENTRY_TABLE_NAME);
		qb.setProjectionMap(sLogEntriesProjectionMap);
		qb.appendWhere(LogEntryColumns._ID + "=" + id);

		String orderBy = LogEntryColumns.DEFAULT_SORT_ORDER;

		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor cursor = qb.query(db, PROJECTION, null, null, null, null, orderBy);

		LogEntry logEntry = null;
		if (cursor.moveToFirst()) {
			logEntry = retrieveLogEntry(cursor);
		}
		return logEntry;
	}

	private LogEntry retrieveLogEntry(Cursor cursor) {
		LogEntry logEntry = new LogEntry();
		logEntry.setId(getId(cursor));
		logEntry.setCreatedDate(getCreatedDate(cursor));
		logEntry.setDescription(getDescription(cursor));
		String tags = getString(cursor, LogEntryColumns.TAGS);
		String[] strings = tags.split(TAG_SEPARATOR);
		for (String string : strings) {
			logEntry.addTag(string);
		}
		return logEntry;
	}

	private Calendar getCreatedDate(Cursor cursor) {
		Long milliseconds = getMilliseconds(cursor, LogEntryColumns.CREATED_DATE);
		if (milliseconds != null) {
			Calendar createdDate = Calendar.getInstance();
			createdDate.setTimeInMillis(milliseconds);
			return createdDate;
		}
		return null;
	}

	private String getDescription(Cursor cursor) {
		return getString(cursor, LogEntryColumns.TITLE);
	}

	private Long getId(Cursor cursor) {
		return getLong(cursor, LogEntryColumns._ID);
	}

	public void delete(LogEntry logEntry) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		db.delete(DatabaseHelper.LOG_ENTRY_TABLE_NAME, LogEntryColumns._ID + "=" + logEntry.getId(), null);
	}

	public Long save(LogEntry logEntry) {
		if (logEntry.getId() == null) {
			return insertNewLogEntry(logEntry);
		} else {
			updateLogEntry(logEntry);
			return logEntry.getId();
		}
	}

	private void updateLogEntry(LogEntry logEntry) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put(LogEntryColumns.TITLE, logEntry.getDescription());
		values.put(LogEntryColumns.TAGS, createTagString(logEntry));
		db.update(DatabaseHelper.LOG_ENTRY_TABLE_NAME, values, LogEntryColumns._ID + "=" + logEntry.getId(), null);
	}

	private Long insertNewLogEntry(LogEntry logEntry) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put(LogEntryColumns.CREATED_DATE, System.currentTimeMillis());
		values.put(LogEntryColumns.TITLE, logEntry.getDescription());
		values.put(LogEntryColumns.TAGS, createTagString(logEntry));
		return db.insert(DatabaseHelper.LOG_ENTRY_TABLE_NAME, LogEntryColumns.TITLE, values);
	}

	private String createTagString(LogEntry logEntry) {
		StringBuilder sb = new StringBuilder();
		List<String> tags = logEntry.getTags();
		for (String tag : tags) {
			sb.append(tag).append(TAG_SEPARATOR);
		}
		return sb.toString();
	}

	static {
		sLogEntriesProjectionMap = new HashMap<String, String>();
		sLogEntriesProjectionMap.put(LogEntryColumns._ID, LogEntryColumns._ID);
		sLogEntriesProjectionMap.put(LogEntryColumns.TITLE, LogEntryColumns.TITLE);
		sLogEntriesProjectionMap.put(LogEntryColumns.CREATED_DATE, LogEntryColumns.CREATED_DATE);
		sLogEntriesProjectionMap.put(LogEntryColumns.TAGS, LogEntryColumns.TAGS);
	}

}
